package com.example.redstarcommerce.cn.dh.user.utils;

/**
 * @ClassName JwtSecrity
 * @Author AndyWu
 * @Date 2024-12-07 9:51
 * @Motto 学不死就往死里学
 * @Version 1.0
 */

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;

@Component
public class JwtSecrity {

    // 密钥，用于签名JWT Token。在实际应用中，请使用更安全的方法来管理密钥
    private String secret = "your-very-secret-key";

    // JWT Token的有效期，单位为秒（这里设置为一天）
    private long jwtExpiration = 86400L;

    /**
     * 生成JWT Token
     *
     * @param userDetails 用户详细信息
     * @return 生成的JWT Token字符串
     */
    public String generateToken(UserDetails userDetails) {
        Map<String, Object> claims = new HashMap<>();
        return createToken(claims, userDetails.getUsername());
    }

    /**
     * 创建JWT Token
     *
     * @param claims 附加的声明信息
     * @param subject 主题（通常是用户名）
     * @return 生成的JWT Token字符串
     */
    private String createToken(Map<String, Object> claims, String subject) {
        return Jwts.builder()
                .setClaims(claims) // 设置附加的声明信息
                .setSubject(subject) // 设置主题（通常是用户名）
                .setIssuedAt(new Date(System.currentTimeMillis())) // 设置签发时间
                .setExpiration(new Date(System.currentTimeMillis() + jwtExpiration * 1000)) // 设置过期时间
                .signWith(SignatureAlgorithm.HS256, secret) // 使用HS256算法和密钥进行签名
                .compact(); // 生成并返回JWT Token字符串
    }

    /**
     * 从JWT Token中获取用户名
     *
     * @param token JWT Token字符串
     * @return 用户名
     */
    public String getUsernameFromToken(String token) {
        return getClaimFromToken(token, Claims::getSubject);
    }

    /**
     * 从JWT Token中获取过期时间
     *
     * @param token JWT Token字符串
     * @return 过期时间
     */
    public Date getExpirationDateFromToken(String token) {
        return getClaimFromToken(token, Claims::getExpiration);
    }

    /**
     * 根据所要获取的声明类型解析JWT Token
     *
     * @param token JWT Token字符串
     * @param claimsResolver 声明解析器
     * @param <T> 返回值类型
     * @return 解析后的声明值
     */
    public <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) {
        final Claims claims = getAllClaimsFromToken(token); // 获取所有声明
        return claimsResolver.apply(claims); // 使用声明解析器解析特定声明
    }

    /**
     * 解析JWT Token中的所有声明
     *
     * @param token JWT Token字符串
     * @return 所有声明
     */
    private Claims getAllClaimsFromToken(String token) {
        return Jwts.parser()
                .setSigningKey(secret) // 设置密钥
                .parseClaimsJws(token) // 解析JWT Token
                .getBody(); // 获取声明部分
    }

    /**
     * 检查JWT Token是否已过期
     *
     * @param token JWT Token字符串
     * @return 如果Token已过期则返回true，否则返回false
     */
    private Boolean isTokenExpired(String token) {
        final Date expiration = getExpirationDateFromToken(token); // 获取Token的过期时间
        return expiration.before(new Date()); // 比较当前时间与过期时间
    }

    /**
     * 验证JWT Token
     *
     * @param token JWT Token字符串
     * @param userDetails 用户详细信息
     * @return 如果Token有效则返回true，否则返回false
     */
    public Boolean validateToken(String token, UserDetails userDetails) {
        final String username = getUsernameFromToken(token); // 从Token中获取用户名
        return (username.equals(userDetails.getUsername()) && !isTokenExpired(token)); // 验证用户名和Token是否过期
    }

}
